package sg.edu.nus.iss.cats.dataaccess.hibernate;

import java.util.Hashtable;

import sg.edu.nus.iss.cats.dataaccess.SequenceManager;
import sg.edu.nus.iss.cats.exception.HibernateAccessLayerException;
import sg.edu.nus.iss.cats.model.SequenceInfo;
public class SequenceManagerImpl extends AbstractDao implements SequenceManager {
	
	private static final int ALLOCATION_SIZE = 1;

	private Hashtable seq = new Hashtable();

	public SequenceManagerImpl() {
		super();
	}

	public int getNextValue(String sequenceName)
			throws HibernateAccessLayerException {
		// Get the sequence info from the table
		SequenceInfo info = (SequenceInfo) seq.get(sequenceName);

		// If there is no sequence info, or we're at the end of our
		// allocation, get the latest allocation from the db
		if ((info == null) || (info.getNextValue() > info.getLastValue())) {
			info = allocateNewValues(sequenceName);
			seq.put(sequenceName, info);
		}

		// Return the first available value and increment
		int result = info.getNextValue();
		info.setNextValue(result + 1);
		return result;
	}

	private SequenceInfo allocateNewValues(String sequenceName)
			throws HibernateAccessLayerException {
		try {
			SequenceInfo info = findSequenceInfo(sequenceName);
			if (info == null) {
				info = startNewSequence(sequenceName);
			}
			int lastValue = info.getLastValue();
			info.setNextValue(lastValue + 1);
			info.setLastValue(lastValue + ALLOCATION_SIZE);
			super.saveOrUpdate(info);
			return info;
		} catch (Throwable t) {
			throw new HibernateAccessLayerException(t.toString());

		}
	}

	private SequenceInfo startNewSequence(String sequenceName)
			throws HibernateAccessLayerException {
		try {
			SequenceInfo info = new SequenceInfo();
			info.setName(sequenceName);
			info.setLastValue(0);
			super.saveOrUpdate(info);
			return info;
		} catch (Throwable t) {
			throw new HibernateAccessLayerException(t.toString());

		}
	}

	public SequenceInfo findSequenceInfo(String sname)
			throws HibernateAccessLayerException {
		System.out.println("Finding Sequence" + sname);
		try {
			return ((SequenceInfo) super.find(SequenceInfo.class,sname));

		} catch (Throwable t) {
			throw new HibernateAccessLayerException(t.toString());
		}
	}
}